<?php
/* {
Citru - www.citru.se
See license.txt for copyright and license information.
} */

if(!defined("_CITRU")) {die('This file should not be accessed directly.');}

abstract class Module {

// Abstract functions
	abstract function __construct($instance, $db_module, $permissions);
	abstract public function getView();
	abstract protected function getAdminTab($tab="view");
	abstract public function installTables();


// View functions

	/**
	 * Returns html for the admin-view of a module. Loads selected tab based on get-value.
	 *
	 * @return string		the html for the selected tab
	 */
	public public function getAdminView() {
		$view = $this->getActiveView();
		$tabs = $this->generateTabs($view);
		$data = $this->getAdminTab($view);
		
		if($view == 'view') {
			// We want the view-mode to render as close to what the user will se as possible
			return $tabs."\n".$data."\n";
		} else {
			return $tabs.'<div class="citru_module_block"><div class="citru_inner_module_block">'."\n".$data."\n".'</div></div>'."\n";
		}
	}
	
	
	/**
	 * Returns which tab is selected in a module
	 *
	 * @return string		the tab that's selected		
	 */	
	private function getActiveView() {
		if(isset($_GET[$this->moduleName.'_'.$this->instanceName])) {
			$view = $_GET[$this->moduleName.'_'.$this->instanceName];
			if(in_array($view, $this->moduleTabs)) {
				return $view;
			}
		} 
		return $this->moduleTabs[0];
	}


// Tabs functions
	/**
	 * Creates a set of tabs for a module
	 * 
	 * @param string $view 		the view/tab that's selected
	 * @return string			html for the tabs
	 */
	private function generateTabs($view) {
		$active_tab[$view] = true;
		$tabdata = '<div class="citru_module_tabs" id="'.$this->moduleName.'_'.$this->instanceName.'">'."\n";

		foreach ($this->moduleTabs as $i => $tab) {
			if($this->permissions[$tab] == true && $tab != '') {
				$tabdata .= $this->generateTab(ucwords($tab), $active_tab[$tab], '');
			}
		}

		$tabdata .= '</div>'."\n";

		return $tabdata;
	}
	
	/**
	 * Creates a html link to a tab in the current module. Get data that should be appended to the link can be specified.
	 *
	 * @param string $tab 			tab/view to make a link to
	 * @param string $extra_gets 	get data that should be included in the link
	 * @return string				html for a link to the specific tab
	 */
	protected function generateTablink($tab, $extra_gets="") {
		$tabdata .= $this->generateTab(ucwords($tab), false, $extra_gets);
		return $tabdata;
	}

	/**
	 * Generates html for a tab
	 *
	 * @param string $name 		name of the tab that should be generated
	 * @param boolean $active 	true if the tab is active
	 * @param string $get 		get data to add to the tabs link
	 * @return string			the generated html
	 */
	private function generateTab($name="View", $active=false, $get="") {
		// Replace with icon if available
		if(file_exists(ROOT.'inc/icons/'.strtolower($name).'.png')) {
			$icon = '<img src="'.ROOT.'inc/icons/'.strtolower($name).'.png" alt="'.$name.'" />';
		}
    	
		if($active) {
			return '<a class="citru_selected">'.$icon.'<span>'.$name.'</span></a>'."\n";
		}
		if($name == "View") {
			return '<a href="?'.$get.'" title="'.$name.'">'.$icon.'<span>'.$name.'</span></a>'."\n";
		}
		return '<a href="?'.$this->moduleName.'_'.$this->instanceName.'='.strtolower($name).'&'.$get.'" title="'.$name.'">'.$icon.'<span>'.$name.'</span></a>'."\n";
	}
	
// Permission functions
	/**
	 * Returns a form for configuring permissions for a module
	 *
	 * @return string			html for the generated permissions form
	 */
	protected function getPermissionsForm() {
		if($this->permissions['permissions'] == false) { return ''; }
		
		// Check if permissions should be saved first.
		if($_POST['instance'] == $this->moduleName.'_'.$this->instanceName && $_POST['action'] == "permissions") {
			if($_POST['new'] == 'true') {
				$message = $this->savePermissions(true);
			} else {
				$message = $this->savePermissions(false);
			}
		}
		
		// Fetch the permissions for the instance and module (glob)
		$row = $this->findPermissionsRow($this->instanceName);
		$row_glob =  $this->findPermissionsRow('');
		
		// if no permissions for the instance is found, mark as new
		$new = 'false';
		if(!$row) { $new = 'true'; }

		$elements = array(array('form_start'),
						  array('hidden_instance'),
						  array('hidden_action', 'value'=>'permissions'),
						  array('hidden_new', 'value'=>$new),
						  array('fieldset_start', 'legend'=>'Permissions (users, @groups)'));
		
		foreach ($this->moduleTabs as $i => $tab) {
			if($tab != '') {
				if($row_glob[strtolower($tab)] != '') { $glob_perms = '<span class="citru_globalpermissions"> + '.$row_glob[strtolower($tab)].'</span><br />'; }
				$perms = preg_replace("/(([,][ ]*)|([ ]+))/", ', ', $row[strtolower($tab)]);	// Make nicely comma separated
				$elements[] = array('label', 'for'=>'permission_'.$tab, 'text'=>'Allowed access to '.$tab.':', 'after'=>'<br />');
				$elements[] = array('input_text', 'class'=>'citru_medium_width', 'name'=>'permission_'.$tab, 'value'=>$perms, 'after'=>$glob_perms);
			}
		}
		
		$elements[] = array('fieldset_end');
		$elements[] = array('footer_start');
		$elements[] = array('custom', 'data'=>$message);
		$elements[] = array('submit', 'value'=>'Save', 'icon'=>'save');
		$elements[] = array('footer_end');
		$elements[] = array('form_end');
		
		$form = $this->generateForm($elements);
		
		return $form;
	}

	/**
	 * Fetches the permissions from the database
	 *
	 * @param string $instance 		the instance to find the permissions row for. Set to null for global permissions.
	 * @return array 				array of permissions data from the database.
	 * 								Contain 'permissions' which is of the format tab=permissions\ntab=permissions
	 */
	private function findPermissionsRow($instance) {
		$params = array(	"table" => "Permissions",
							"columns" => "permissions",
							"condition" =>	array(
											array( "module", "=", $this->moduleName, "AND" ),
											array( "instance", "=", $instance, "" ) ));
		
		$db_permissions = $this->dbModule->findFirst($params);
		if(!$db_permissions) { return false; }
		$permissions_rows = split("\n", $db_permissions['permissions']);
		foreach($permissions_rows as $row) {
			$tmp = split("=", $row);
			$key = trim($tmp[0]);
			$val = trim($tmp[1]);
			$permissions[$key] = $val;
		}
		
		return $permissions;
	}
	
	/**
	 * Saves the permissions to the database
	 *
	 * @param boolean $new 		true if a permissions row should be created first
	 * @return string			html with message of what happend
	 */
	private function savePermissions($new = false) {
		if($new) { $this->createPermissionsRow(); }
		
		foreach ($this->moduleTabs as $i => $tab) {
			if($tab != '') {
				$data = $_POST['permission_'.$tab];
				if(!preg_match('/[^A-Za-z0-9@, ]+/', $data)) {
					$set_data .= $tab.'='.$data."\n";
				}
			}
		}
		
		$set['permissions']=$set_data;
		
		$condition = array( array( "module", "=", $this->moduleName, "AND" ),
							array( "instance", "=", $this->instanceName, "" ));
		
		$params = array( 'table' => 'Permissions',
						 'condition' => $condition,
						 'set' => $set );					
		
		$result = $this->dbModule->updateRow($params);
		
		return '<p class="citru_event">Permissions saved.</p>';
	}

	/**
	 * Creates a new permissions row for a module in the database
	 *
	 * @return void
	 */	
	private function createPermissionsRow() {
		$params = array( 'table' => 'Permissions',
						 'set' => array( 'module' => $this->moduleName,
										 'instance' => $this->instanceName ));
		$this->dbModule->insertRow($params);
	}


// Settings functions

	/**
	 * Returns a row from the database with settings. Can be parsed with parseSettings
	 *
	 * @return array 	array with row from the database. Only on column, 'settings'.
	 */
	protected function findSettingsRow() {
		$params = array(	"table" => $this->moduleName,
							"columns" => "settings",
							"condition" =>	array(
											array( "instance", "=", $this->instanceName, "" ) ));

		$row = $this->dbModule->findFirst($params);
		return $row;
	}

	/**
	 * Parses settings for a module.
	 *
	 * @param string $s 		String with settings to be parsed in the format key=value\nkey=value
	 * @return array 			an array in the format 'key'=>'value', 'key'=>'value'
	 */	
	protected function parseSettings($s) {
		$s_rows = split("\n", $s);
		$settings = array();
		foreach($s_rows as $row) {
			$tmp = split("=", $row);
			$settings[$tmp[0]] = trim($tmp[1]);
		}
		return $settings;
	}


// Helper functions
	
	/**
	 * Generates a form by calling FormBuilder. Simplifies the use for the modules.
	 * @see FormBuilder
	 * 
	 * @param array $elements 		array of elements to create an form from. See FormBuilder for details.
	 * @return string				html for the generated form
	 */
	protected function generateForm($elements=array()) {
		return FormBuilder::generateForm($elements, $this->moduleName, $this->instanceName);
	}
	
	/**
	 * creates a row in the database for a moduleinstance
	 *
	 * @return void
	 */
	protected function createDataRow() {
            $params = array( 'table' => $this->moduleName,
                                             'set' => array( 'instance' => $this->instanceName ));
            $this->dbModule->insertRow($params);
    }
	
	/**
	 * Takes an array and returns a string of keys and values with glue inbetween
	 *
	 * @param array $array 		array to implode
	 * @param string $inglue 	glue between key and value
	 * @param string $outglue 	glue between key-value pairs
	 * @return string 			imploded array as a string
	 */
	private function implode_with_key($array=array(), $inglue = '=', $outglue = '&') {
    	$return = '';
    	foreach ($array as $key => $val) {
    	    $return .= $outglue . $key . $inglue . $val;
    	}
    	return substr($return,strlen($outglue));
    }

	/**
	 * Encodes checkboxes to checked/null instead of true/false
	 *
	 * @param string $string 	string to convert
	 * @return string			converted string
	 */
	protected function checkboxEncode($string) {
		if ($string == 'true'):
		 	return 'checked'; 
		else:
			return ''; 
		endif;
	}

	/**
	 * Decodes checkboxes to true/false instead of on/null
	 *
	 * @param string $string 	string to convert
	 * @return string			converted string	
	 */
	protected function checkboxDecode($string) {
		if ($string == 'on'):
		 	return 'true'; 
		else:
			return 'false'; 
		endif;
	}
	
}

?>
